//*****************************************************************************
// JFab (http://code.google.com/p/jfab)
// Copyright (c) 2011 JFab.org
// Admin jfab@jeffreythompson.net
//
// See the file "LICENSE.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//*****************************************************************************

package org.jfab.core.factory;

import org.jfab.core.adapter.Adapter;
import org.jfab.core.adapter.AdapterInjector;
import org.jfab.core.adapter.DefaultAdapterInjector;
import org.jfab.core.comparator.CGTypeComparator;
import org.jfab.core.model.CGType;
import org.jfab.core.model.CGTypeUtilities;
import org.jfab.core.model.DefaultModelInjector;
import org.jfab.core.model.ModelInjector;

/**
 * Provides a default factory injector.
 * <p>
 * THIS INJECTOR HAS STATE: it caches a reference to a
 * <code>TypeReferenceSupport</code> object. Subsequent calls to
 * injectTypeReferenceSupport return the initial object.
 * </p>
 */
public class DefaultFactoryInjector implements FactoryInjector
{
    /** Adapter injector. */
    private final AdapterInjector _adapterInjector;

    /** Model injector. */
    private final ModelInjector _modelInjector;

    /** Cached type reference support. */
    private TypeReferenceSupport _typeReferenceSupport;

    /**
     * Construct this object.
     */
    public DefaultFactoryInjector()
    {
        this(new DefaultAdapterInjector(), new DefaultModelInjector());
    }

    /**
     * Construct this object with the given parameter.
     * 
     * @param adapterInjector Adapter injector.
     * @param modelInjector Model injector.
     */
    public DefaultFactoryInjector(final AdapterInjector adapterInjector,
            final ModelInjector modelInjector)
    {
        _adapterInjector = adapterInjector;
        _modelInjector = modelInjector;
    }

    @Override
    public CGAnnotationFactory injectCGAnnotationFactory()
    {
        return new DefaultCGAnnotationFactory(injectCGTypeFactory());
    }

    @Override
    public CGClassFactory injectCGClassFactory()
    {
        return new DefaultCGClassFactory();
    }

    @Override
    public CGConstructorFactory injectCGConstructorFactory()
    {
        return new DefaultCGConstructorFactory();
    }

    @Override
    public CGEnumFactory injectCGEnumFactory()
    {
        return new DefaultCGEnumFactory();
    }

    @Override
    public CGEnumItemFactory injectCGEnumItemFactory()
    {
        return new DefaultCGEnumItemFactory();
    }

    @Override
    public CGFieldFactory injectCGFieldFactory()
    {
        return new DefaultCGFieldFactory(injectStringFactory(),
                injectCGTypeFactory());
    }

    @Override
    public CGInterfaceFactory injectCGInterfaceFactory()
    {
        return new DefaultCGInterfaceFactory();
    }

    @Override
    public CGMethodDeclarationFactory injectCGMethodDeclarationFactory()
    {
        return new DefaultCGMethodDeclarationFactory(injectCGTypeFactory(),
                injectStringFactory(), injectCGParameterFactory());
    }

    @Override
    public CGMethodFactory injectCGMethodFactory()
    {
        return new DefaultCGMethodFactory(injectCGTypeUtilities(),
                injectCGTypeFactory(), injectTypeReferenceSupport(),
                injectStringFactory(), injectCGAnnotationFactory(),
                injectCGParameterFactory(), injectCGMethodDeclarationFactory());
    }

    @Override
    public CGParameterFactory injectCGParameterFactory()
    {
        return new DefaultCGParameterFactory();
    }

    @Override
    public CGPropertyFactory injectCGPropertyFactory()
    {
        return new DefaultCGPropertyFactory(injectStringFactory());
    }

    @Override
    public CGTypeFactory injectCGTypeFactory()
    {
        return new DefaultCGTypeFactory(injectCGTypeAdapter());
    }

    @Override
    public InstanceFactory injectInstanceFactory()
    {
        return new DefaultInstanceFactory();
    }

    @Override
    public StringFactory injectStringFactory()
    {
        return new DefaultStringFactory(injectCGTypeUtilities(),
                injectTypeReferenceSupport());
    }

    @Override
    public TypeReferenceSupport injectTypeReferenceSupport()
    {
        if (_typeReferenceSupport == null)
        {
            _typeReferenceSupport = new DefaultTypeReferenceSupport(
                    "placeholder", injectCGTypeUtilities(),
                    injectCGTypeFactory(), new CGTypeComparator(
                            injectCGTypeUtilities()));
        }

        return _typeReferenceSupport;
    }

    /**
     * @return the adapterInjector
     */
    private AdapterInjector getAdapterInjector()
    {
        return _adapterInjector;
    }

    /**
     * @return the modelInjector
     */
    private ModelInjector getModelInjector()
    {
        return _modelInjector;
    }

    /**
     * @return a new code generator type adapter.
     */
    private Adapter<CGType> injectCGTypeAdapter()
    {
        return getAdapterInjector().injectCGTypeAdapter();
    }

    /**
     * @return a new type utilities.
     */
    private CGTypeUtilities injectCGTypeUtilities()
    {
        return getModelInjector().injectCGTypeUtilities();
    }
}
